﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Collections;
using System.Threading;
/*
 * Project Home : http://code.google.com/p/klsudoku
 * Project Owner: ttylikl@gmail.com Email:ttylikl@qq.com
 * Project Blog : http://www.cnblogs.com/ttylikl
 * All Files of this project is free to use , but you should keep the information above when you copy&use it.
 * Infomation Modify Date: 2009.02.22
 * 
 * */

namespace SudokuPanel
{
    //解题模块，命令解释模块
    /*
     * 算法函数可以使用委派
     * 关键路径以命令包为单位存储
     * 每个命令包包含若干命令
     * 命令及参数如下：
     * set x,y,num
     * unset x,y
     * tag x,y,num,flag
     */
    //主窗口，表现模块
    public delegate void EventPuzzleChanged(List<int[]> nodes);

    public class operation
    {
        public enum opname { set_number, unset_number, set_candidate_none, set_candidate_tag, set_candidate_untag };
        public enum SolveHelper //应该再分细一些，即使一个Helper函数，也有可能使用了多个解法，比如SingleNumber包含了显示
        {
            Manual = 0, NakedSingleNumber, HiddenSingleNumber, IntersectionRemoval, NakedPair, NakedTriple, NakedQuad,
            HiddenPair, HiddenTriple, HiddenQuad, X_Wing, SwordFish, XY_Wing, JellyFish, XYZ_Wing,/*Y_Wing,*/ BUG1, W_WING, X_Chain, XY_Chain,
            UniqueRectangle1, UniqueRectangle2, UniqueRectangle3, UniqueRectangle4, UniqueRectangle5, UniqueRectangle6, UniqueRectangle7,
            //Bug1,
            Forcing_Chain, Guess
        };
        public static int lvl(SolveHelper helper)
        {
            //容易，普通，困难，极难，骨灰
            switch (helper)
            {
                case SolveHelper.Manual:
                case SolveHelper.HiddenSingleNumber:
                case SolveHelper.NakedSingleNumber:
                case SolveHelper.IntersectionRemoval:
                case SolveHelper.NakedPair:
                case SolveHelper.HiddenPair:
                    return 1;
                case SolveHelper.NakedTriple:
                case SolveHelper.HiddenTriple:
                case SolveHelper.NakedQuad:
                case SolveHelper.HiddenQuad:
                //case SolveHelper.Y_Wing:
                    return 2;
                case SolveHelper.X_Wing:
                case SolveHelper.BUG1:
                case operation.SolveHelper.UniqueRectangle1:
                case operation.SolveHelper.UniqueRectangle2:
                case operation.SolveHelper.UniqueRectangle3:
                case operation.SolveHelper.UniqueRectangle4:
                case operation.SolveHelper.UniqueRectangle5:
                case operation.SolveHelper.UniqueRectangle6:
                case operation.SolveHelper.UniqueRectangle7:
                //case operation.SolveHelper.Bug1:
                    return 3;
                case SolveHelper.XY_Wing:
                case SolveHelper.XYZ_Wing:
                case SolveHelper.SwordFish:
                    return 4;
                case SolveHelper.JellyFish:
                case SolveHelper.X_Chain:
                case SolveHelper.XY_Chain:
                    return 5;
                case SolveHelper.Forcing_Chain:
                case SolveHelper.Guess:
                default:
                    return 6;

            }
        }

        public opname m_op;//操作类型
        public Point[] m_points;//操作坐标
        public int[] values;//操作的值参数

        //辅助传递提示信息的
        public List<int[]> tip_chain = null;//传递推导链
        public int[] tip_chain_head = null;//推导链的首节点
        public List<iterator> tip_itor = null;
        public List<Point> tip_points = null;
        public List<int> tip_number = null;

        public String info;
        public SolveHelper helper;
        public operation(SolveHelper helper, opname op, Point[] p, int[] values, String str)
        {
            m_op = op;
            m_points = p;
            this.values = values;
            info = str;
            this.helper = helper;
        }
    }


    public class solver
    {

        private number[,] nums;
        private puzzle pz;
        public bool isSingleStep = true;//默认有提示就不继续搜索了
        public bool single_solution = true;
        public List<operation> ops = new List<operation>();
        public List<List<operation>> opsteps = new List<List<operation>>();
        volatile bool showdebuginfo = false;
        public int max_recurise = 15; //在寻找链的时候，默认最多搜索15个节点，太多的已经无意义了。
        public solver(puzzle pz)
        {
            this.pz = pz;
            this.nums = pz.m_numbers;

            _strResult = "";//清除终局数据

            //优选的算法应该先添加到委托里，需要注意效率的问题


            findTip += helper_SingleNumber; //唯一数法
            findTip += helper_IntersectionRemoval;//区块删减法
            findTip += helper_NakedNumberSet;
            findTip += helper_HiddenNumberSet;
            findTip += helper_XY_Wing;
            //重复，废弃findTip += helper_Y_Wing;
            findTip += helper_XYZ_Wing;
            findTip += helper_Fish;//X-Wing,SwordFish,JellyFish
            findTip += helper_UniqueRectangle;
            findTip += helper_bug_1;
            findTip += helper_X_Chain;
            findTip += helper_XY_Chain;
            findTip += helper_Forcing_Chain;
            findTip += helper_Guess;
        }
        public String logstr = "";

        //考虑使用评分机制，对出现的技巧和其他因素（比如填数间隔，连续难度技巧数量）

        //新的难度计算函数
        //先对技巧分为5级      容易，普通，困难，极难，骨灰
        //容易：连续删除候选数的操作小于2步，中间不能有超过1级的技巧
        //普通：连续删除候选数的操作小于5步，中间不能有超过3级的技巧
        //困难：连续删除候选数的操作小于10步，中间不能有超过4级的技巧
        //极难：连续删除候选数的操作多于10步，中间只有3-4级的技巧
        //骨灰：有超过4级技巧的题目
        public static int get_lvl(String str)
        {
            dlx_solver ds = new dlx_solver();
            String strResult = ds.do_solve(str);
            int scnt = ds.solution_count(str);
            //Debug.WriteLine("DLX:" + strResult);
            if (scnt == 0)
                return 0;
            puzzle pz = new puzzle();
            pz.loadPuzzle(str);
            solver so = new solver(pz);
            so.isSingleStep = true;
            if (!so.do_solve())
                return 0;
            int[] lvlstep = new int[] { 3, 6, 11 };//因为是两个set_number操作相减，所以还应该+1才是正确的删除步骤判断
            int[] lvlskl = new int[] { 1, 2, 3, 4 };
            int l = 1;
            int lsn = 0;
            int lsk = 1;
            for (int i = 0; i < so.opsteps.Count; ++i)
            {
                operation op = so.opsteps[i][0];

                int oplvl = operation.lvl(op.helper);
                //这里会出现需要判断的解题技巧
                if (oplvl > lsk)
                    lsk = oplvl;
                if (op.m_op == operation.opname.set_number)
                {
                    int oldlsn = lsn;
                    int oldsk = lsk;
                    lsn = i;
                    lsk = 1;
                    //骨灰
                    if (oplvl > lvlskl[3])//有超过4级技巧的题目
                    {
                        return 5;//最大难度的题目
                    }
                    //极难
                    if (oldsk == lvlskl[3] || (oldlsn < i - lvlstep[2] && oldsk >= lvlskl[2])) //删除操作连续10步以上且技巧为3级技巧  或者 4级技巧
                    {
                        l = 4;
                        continue;
                    }
                    if (l == 4) continue;
                    //困难
                    if (oldlsn < i - lvlstep[1] || oldsk >= lvlskl[2]) //删除操作连续5步以上或者技巧为3级技巧
                    {
                        l = 3;
                        continue;
                    }
                    if (l == 3) continue;
                    //普通
                    if (oldlsn < i - lvlstep[0] || oldsk >= lvlskl[1]) //删除操作连续2步以上或者技巧为2级技巧
                    {
                        l = 2;
                        continue;
                    }
                    //容易
                }
            }
            return l;
        }
        public bool do_solve()
        {
            while (run(1)) ;// Thread.Sleep(10);
            return (pz.getPuzzleStatus() == puzzle.Status.SUCCESS);
        }
        public bool background = false;
        public bool run(int steps)
        {
            while (steps-- > 0) //暂时不无穷循环下去
            {
                if (background)
                    Thread.Sleep(10);
                List<operation> opstip = getTip();
                if (!this.single_solution) //多解题不做处理
                {
                    return false;
                }
                if (opstip.Count == 0)
                {
                    return false;
                }
                //解析operation，执行操作
                if (showdebuginfo) Debug.WriteLine("得到" + opstip.Count + "个提示，开始解题。。。");
                opsteps.Add(opstip);
                foreach (operation op in opstip)
                {
                    this.ops.Add(op);
                    if (showdebuginfo) Debug.WriteLine(op.info);
                    logstr += op.info + "\r\n";
                    switch (op.m_op)
                    {
                        case operation.opname.set_number:
                            if (op.helper == operation.SolveHelper.Guess)
                            {
                                //这个情况只对第一个Point和第一个num进行操作
                                pz[op.m_points[0]] = op.values[0];
                            }
                            else
                            {
                                foreach (Point p in op.m_points)
                                {
                                    foreach (int num in op.values)
                                    {
                                        pz[p] = num;
                                    }
                                }
                            }
                            break;
                        case operation.opname.set_candidate_none:
                            foreach (Point p in op.m_points)
                            {
                                foreach (int num in op.values)
                                {
                                    pz[p, num] = 0;
                                }
                            }
                            break;
                        //自动解题不会出现下面的情况
                        //case operation.opname.unset_number:
                    }
                }
                puzzle.Status st = pz.getPuzzleStatus();
                if (st == puzzle.Status.SUCCESS)
                {
                    if (showdebuginfo) Debug.WriteLine("sudoku is solved!");
                    return true;
                }
                else if (st == puzzle.Status.ERROR)
                {
                    if (showdebuginfo) Debug.WriteLine("sudoku has wrong step!");
                    return false;
                }
            }
            return true;
        }

        public List<operation> getTip()
        {
            List<operation> ret = new List<operation>();
            //TODO:考虑使用异常来终止委派调用链表
            bool bOldSingleStep = isSingleStep;
            isSingleStep = true;
            findTip(ret);
            isSingleStep = bOldSingleStep;
            return ret;
        }

        delegate void delegateFindTip(List<operation> ops);
        private delegateFindTip findTip;


        ////全部有candnum个候选数的数格集合
        //private List<number> numbers_with_candidates(int candnum)
        //{
        //    List<number> ret = new List<number>();
        //    foreach (number num in nums)
        //    {
        //        if (num.candidates().Length == candnum)
        //        {
        //            ret.Add(num);
        //        }
        //    }
        //    return ret;
        //}

        void helper_SingleNumber(List<operation> ops)
        {
            if (ops.Count > 0)
                return;
            if (showdebuginfo) Debug.WriteLine("唯一候选数法 (Naked Single and Hidden Single)");
            List<iterator> its = new List<iterator>();
            for (int loop = 1; loop <= 9; ++loop)
            {
                its.Add(new iteratorX(nums, new Point(1, loop)));
                its.Add(new iteratorY(nums, new Point(loop, 1)));
                its.Add(new iteratorZ(nums, pubfun.basepoints[loop - 1]));
            }
            foreach (number num in nums)
            {
                int[] cands = num.candidates();
                if (cands.Length == 1)
                {
                    int cand = cands[0];

                    //检测避免添加重复的point
                    bool isoverlap = false;
                    if (ops.Count > 0)
                    {
                        foreach (operation op in ops)
                        {
                            if (pubfun.find(op.m_points, num.xy))
                            {
                                isoverlap = true;
                                break;
                            }
                        }
                    }
                    if (!isoverlap)
                    {
                        operation.SolveHelper helper = operation.SolveHelper.NakedSingleNumber;
                        String str = pubfun.strPoint(num.xy) + "=" + cand + "：单元格" + pubfun.strPoint(num.xy) + "的候选数" + cand + "是唯一显式候选数";
                        operation op = new operation(helper, operation.opname.set_number, new Point[] { num.xy }, new int[] { cand }, str);
                        ops.Add(op);
                        //if (isSingleStep) return;
                    }
                }
            }
            foreach (iterator it in its)
            {
                for (int cand = 1; cand <= 9; ++cand)
                {

                    List<int> nl = new List<int>();
                    for (int pos = 0; pos < 9; ++pos)
                    {
                        if (it[pos][cand - 1] == pubfun.Flag.normal)
                            nl.Add(pos);
                    }
                    if (nl.Count == 1)
                    {
                        number num = it[nl[0]];
                        bool isNaked = (num.candidates().Length == 1);
                        if (!isNaked)
                        {
                            //检测避免添加重复的point
                            bool isoverlap = false;
                            if (ops.Count > 0)
                            {
                                foreach (operation op in ops)
                                {
                                    if (pubfun.find(op.m_points, num.xy))
                                    {
                                        isoverlap = true;
                                        break;
                                    }
                                }
                            }
                            if (!isoverlap)
                            {
                                operation.SolveHelper helper = (isNaked ? operation.SolveHelper.NakedSingleNumber : operation.SolveHelper.HiddenSingleNumber);
                                String str = pubfun.strPoint(num.xy) + "=" + cand + "：单元格" + pubfun.strPoint(num.xy) + "的候选数" + cand +
                                    "是" + pubfun.strIteratorName(it) + "唯一" + (isNaked ? "显式" : "隐式") + "候选数";
                                operation op = new operation(helper, operation.opname.set_number, new Point[] { num.xy }, new int[] { cand }, str);
                                op.tip_itor = new List<iterator>();
                                op.tip_itor.Add(it);
                                ops.Add(op);
                                //if (isSingleStep) return;
                            }
                        }
                    }
                }
            }
        }


        /*
         * 在某一区块中，当所有可能出现某个数字的单元格都位于同一行时，就可以把这个数字从该行的其他单元格的候选数中删除。
         * 在某一区块中，当所有可能出现某个数字的单元格都位于同一列时，就可以把这个数字从该列的其他单元格的候选数中删除。
         * 在某一行（列）中，当所有可能出现某个数字的单元格都位于同一区块中时，就可以把这个数字从该区块的其他单元格的候选数中删除。
        */
        //区块删减法 (Intersection Removal)
        void helper_IntersectionRemoval(List<operation> ops)
        {
            if (ops.Count > 0)//如果已经有解，则不进一步处理
                return;
            operation.SolveHelper helper = operation.SolveHelper.IntersectionRemoval;
            if (showdebuginfo) Debug.WriteLine("区块删减法 (Intersection Removal)");
            for (int i = 1; i <= 9; ++i)
            {
                //if(showdebuginfo) Debug.WriteLine("第" + i + "轮循环处理");
                Point p1 = new Point(i, 1);
                Point p2 = new Point(1, i);
                Point p3 = pubfun.basepoints[i - 1];
                iteratorZ itorz = new iteratorZ(pz.m_numbers, p3);
                iteratorX itorx = new iteratorX(pz.m_numbers, p2);
                iteratorY itory = new iteratorY(pz.m_numbers, p1);

                //第一步按行/列观察的区块删除法
                #region 第一步按行/列观察的区块删除法
                int[,] cx = new int[,]{
                    { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    { 0, 0, 0, 0, 0, 0, 0, 0, 0 }
                    };
                int[,] cy = new int[,]{
                    { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    { 0, 0, 0, 0, 0, 0, 0, 0, 0 }
                    };
                //将行列的候选数分3段分别相加计次
                for (int idx = 0; idx < 9; ++idx) //迭代器的索引下标
                {
                    //if(showdebuginfo) Debug.WriteLine(itory[idx].xy +" " +itorx[idx].xy);
                    for (int j = 0; j < 9; ++j) //计数器的下标
                    {
                        cy[idx / 3, j] += (itory[idx][j] == pubfun.Flag.normal) ? 1 : 0;
                        cx[idx / 3, j] += (itorx[idx][j] == pubfun.Flag.normal) ? 1 : 0;
                    }
                }
                //分析3段里，每个候选数的情况
                #region 先按行分析
                for (int n = 1; n <= 9; ++n)
                {
                    Point p;
                    iteratorZ itz;
                    int sec;
                    if (cx[0, n - 1] > 0 && cx[1, n - 1] == 0 && cx[2, n - 1] == 0) //候选数n存在于第一段
                        sec = 0;
                    else if (cx[0, n - 1] == 0 && cx[1, n - 1] > 0 && cx[2, n - 1] == 0)
                        sec = 1;
                    else if (cx[0, n - 1] == 0 && cx[1, n - 1] == 0 && cx[2, n - 1] > 0)
                        sec = 2;
                    else
                        continue;
                    //得到该段的Z迭代器，此迭代器内对X坐标与p.X相同以外的候选数n都应该排除
                    //if(showdebuginfo) Debug.WriteLine("第" + i+ "行，候选数"+n+"只存在于第" + (sec+1)+"段");
                    p = itorx[sec * 3].xy;
                    itz = new iteratorZ(pz.m_numbers, p);

                    List<Point> lps = new List<Point>();
                    foreach (number num in itz)
                    {
                        if (num.xy.Y != p.Y && num[n - 1] == pubfun.Flag.normal)
                        {
                            lps.Add(num.xy);
                        }

                    }
                    //区块排除数
                    if (lps.Count > 0)
                    {
                        String str = "第" + pubfun.strRowName(i) + "行，候选数" + n + "只存在于第" + (sec + 1) + "段，排除所在方块" + pubfun.strIteratorName(itz) +
                            "里的数格" + pubfun.strPoints(lps) + "里的侯选数 " + n;
                        if (showdebuginfo) Debug.WriteLine(str);
                        operation op = new operation(helper, operation.opname.set_candidate_none, lps.ToArray(), new int[] { n }, str);
                        op.tip_itor = new List<iterator>();
                        op.tip_itor.Add(new iteratorX(nums, new Point(1, i)));
                        op.tip_itor.Add(itz);
                        ops.Add(op);
                        if (isSingleStep) return;
                    }
                }
                #endregion
                #region 再按列分析
                for (int n = 1; n <= 9; ++n)
                {
                    Point p;
                    iteratorZ itz;
                    int sec;

                    if (cy[0, n - 1] > 0 && cy[1, n - 1] == 0 && cy[2, n - 1] == 0) //候选数n存在于第一段
                        sec = 0;
                    else if (cy[0, n - 1] == 0 && cy[1, n - 1] > 0 && cy[2, n - 1] == 0)
                        sec = 1;
                    else if (cy[0, n - 1] == 0 && cy[1, n - 1] == 0 && cy[2, n - 1] > 0)
                        sec = 2;
                    else
                        continue;
                    //得到该段的Z迭代器，此迭代器内对Y坐标与p.Y相同以外的候选数n都应该排除
                    p = itory[sec * 3].xy;
                    itz = new iteratorZ(pz.m_numbers, p);
                    //if(showdebuginfo) Debug.WriteLine("第" + i + "列，候选数" + n + "只存在于第" + (sec + 1) + "段");
                    List<Point> lps = new List<Point>();
                    foreach (number num in itz)
                    {
                        if (num.xy.X != p.X && num[n - 1] == pubfun.Flag.normal)
                        {
                            lps.Add(num.xy);
                        }

                    }
                    //区块排除数
                    if (lps.Count > 0)
                    {
                        String str = "第" + i + "列，候选数" + n + "只存在于第" + (sec + 1) + "段，排除所在方块" + pubfun.strIteratorName(itz) +
                            "里的数格" + pubfun.strPoints(lps) + "里的侯选数 " + n;
                        if (showdebuginfo) Debug.WriteLine(str);
                        operation op = new operation(helper, operation.opname.set_candidate_none, lps.ToArray(), new int[] { n }, str);
                        op.tip_itor = new List<iterator>();
                        op.tip_itor.Add(new iteratorY(nums, new Point(i, 1)));
                        op.tip_itor.Add(itz);
                        ops.Add(op);
                        if (isSingleStep) return;
                    }
                }
                #endregion
                #endregion
                //第二步、观察itorz里的同行或者同列的候选数
                #region 第二步、观察itorz里的同行或者同列的候选数
                cx = new int[,]{
                    { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    { 0, 0, 0, 0, 0, 0, 0, 0, 0 }
                    };
                cy = new int[,]{
                    { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    { 0, 0, 0, 0, 0, 0, 0, 0, 0 }
                    };

                for (int n = 0; n < 9; ++n) //逐个候选数进行查找
                {
                    cx[0, n] = ((itorz[0, n] == pubfun.Flag.normal) ? 1 : 0) + ((itorz[1, n] == pubfun.Flag.normal) ? 1 : 0) + ((itorz[2, n] == pubfun.Flag.normal) ? 1 : 0);
                    cx[1, n] = ((itorz[3, n] == pubfun.Flag.normal) ? 1 : 0) + ((itorz[4, n] == pubfun.Flag.normal) ? 1 : 0) + ((itorz[5, n] == pubfun.Flag.normal) ? 1 : 0);
                    cx[2, n] = ((itorz[6, n] == pubfun.Flag.normal) ? 1 : 0) + ((itorz[7, n] == pubfun.Flag.normal) ? 1 : 0) + ((itorz[8, n] == pubfun.Flag.normal) ? 1 : 0);

                    cy[0, n] = ((itorz[0, n] == pubfun.Flag.normal) ? 1 : 0) + ((itorz[3, n] == pubfun.Flag.normal) ? 1 : 0) + ((itorz[6, n] == pubfun.Flag.normal) ? 1 : 0);
                    cy[1, n] = ((itorz[1, n] == pubfun.Flag.normal) ? 1 : 0) + ((itorz[4, n] == pubfun.Flag.normal) ? 1 : 0) + ((itorz[7, n] == pubfun.Flag.normal) ? 1 : 0);
                    cy[2, n] = ((itorz[2, n] == pubfun.Flag.normal) ? 1 : 0) + ((itorz[5, n] == pubfun.Flag.normal) ? 1 : 0) + ((itorz[8, n] == pubfun.Flag.normal) ? 1 : 0);
                }
                //分析3段里，每个候选数的情况
                //先按行分析
                #region
                for (int n = 1; n <= 9; ++n)
                {
                    Point p;
                    iteratorX itx;
                    int sec;
                    if (cx[0, n - 1] > 0 && cx[1, n - 1] == 0 && cx[2, n - 1] == 0) //候选数n存在于第一段
                        sec = 0;
                    else if (cx[0, n - 1] == 0 && cx[1, n - 1] > 0 && cx[2, n - 1] == 0)
                        sec = 1;
                    else if (cx[0, n - 1] == 0 && cx[1, n - 1] == 0 && cx[2, n - 1] > 0)
                        sec = 2;
                    else
                        continue;
                    //得到该段的Z迭代器，此迭代器内对X坐标与p.X相同以外的候选数n都应该排除
                    p = itorz[sec * 3].xy;
                    itx = new iteratorX(pz.m_numbers, p);
                    //if(showdebuginfo) Debug.WriteLine("矩形方块" + itorz.begin().value().xy + "->" + itorz.end().value().xy +"只在" + p.Y + "行存在候选数" + n);
                    List<Point> lps = new List<Point>();
                    foreach (number num in itx)
                    {
                        if ((num.xy.X < p.X || num.xy.X > p.X + 2) && num[n - 1] == pubfun.Flag.normal)
                        {
                            //区块排除数
                            lps.Add(num.xy);
                        }

                    }
                    if (lps.Count > 0)
                    {
                        Char ch = (Char)('A' + p.Y - 1);
                        String str = "矩形方块" + pubfun.strIteratorName(itorz) +
                            "只在" + ch + "行存在候选数" + n + "，排除第" + ch + "行第" + ((p.X - 1) / 3 + 1) + "段以外的数格" + pubfun.strPoints(lps) + "里的候选数 " + n;
                        if (showdebuginfo) Debug.WriteLine(str);
                        operation op = new operation(helper, operation.opname.set_candidate_none, lps.ToArray(), new int[] { n }, str);
                        op.tip_itor = new List<iterator>();
                        op.tip_itor.Add(itorz);
                        op.tip_itor.Add(new iteratorX(nums, new Point(1, p.Y)));
                        ops.Add(op);
                        if (isSingleStep) return;
                    }
                }
                #endregion
                //再按列分析
                #region
                for (int n = 1; n <= 9; ++n)
                {
                    Point p;
                    iteratorY ity;
                    int sec;
                    if (cy[0, n - 1] > 0 && cy[1, n - 1] == 0 && cy[2, n - 1] == 0) //候选数n存在于第一段
                        sec = 0;
                    else if (cy[0, n - 1] == 0 && cy[1, n - 1] > 0 && cy[2, n - 1] == 0)
                        sec = 1;
                    else if (cy[0, n - 1] == 0 && cy[1, n - 1] == 0 && cy[2, n - 1] > 0)
                        sec = 2;
                    else
                        continue;
                    p = itorz[sec].xy;
                    ity = new iteratorY(pz.m_numbers, p);
                    //if(showdebuginfo) Debug.WriteLine( "矩形方块" + itorz.begin().value().xy + "->" + itorz.end().value().xy +"只在" + p.X + "列存在候选数" + n);
                    List<Point> lps = new List<Point>();
                    foreach (number num in ity)
                    {
                        if ((num.xy.Y < p.Y || num.xy.Y > p.Y + 2) && num[n - 1] == pubfun.Flag.normal)
                        {
                            lps.Add(num.xy);
                        }

                    }
                    if (lps.Count > 0)
                    {
                        //区块排除数
                        String str = "矩形方块" + pubfun.strIteratorName(itorz) +
                            "只在" + p.X + "列存在候选数" + n + "，排除第" + p.X + "列第" + ((p.Y - 1) / 3 + 1) + "段以外的数格" + pubfun.strPoints(lps) + "里的候选数 " + n;
                        if (showdebuginfo) Debug.WriteLine(str);
                        operation op = new operation(helper, operation.opname.set_candidate_none, lps.ToArray(), new int[] { n }, str);
                        op.tip_itor = new List<iterator>();
                        op.tip_itor.Add(itorz);
                        op.tip_itor.Add(new iteratorY(nums, new Point(p.X, 1)));
                        ops.Add(op);
                        if (isSingleStep) return;
                    }
                }
                #endregion
                #endregion
            }
        }


        //显式三数集法 (Naked Triplet)
        //显式四数集法 (Naked Quad) 
        void helper_NakedNumberSet(List<operation> ops)
        {
            if (ops.Count > 0)//如果已经有解，则不进一步处理
                return;
            operation.SolveHelper helper = operation.SolveHelper.NakedPair;
            foreach (int dim in new int[] { 2, 3, 4 })
            {
                int[,] comb = null;
                switch (dim)
                {
                    case 2:
                        helper = operation.SolveHelper.NakedPair;
                        comb = pubfun.comb2;
                        break;
                    case 3:
                        helper = operation.SolveHelper.NakedTriple;
                        comb = pubfun.comb3;
                        break;
                    case 4:
                        helper = operation.SolveHelper.NakedQuad;
                        comb = pubfun.comb4;
                        break;
                }
                for (int loop = 1; loop <= 9; ++loop)
                {
                    //if(showdebuginfo) Debug.WriteLine("第" + loop + "轮循环处理，dim=" + dim);
                    Point p1 = new Point(loop, 1);
                    Point p2 = new Point(1, loop);
                    Point p3 = pubfun.basepoints[loop - 1];
                    iterator[] its = new iterator[] { 
                        new iteratorX(pz.m_numbers, p2), 
                        new iteratorY(pz.m_numbers, p1), 
                        new iteratorZ(pz.m_numbers, p3), 
                    };
                    foreach (iterator it in its)
                    {
                        List<number> numlist = new List<number>();
                        //if(showdebuginfo) Debug.WriteLine("分析区块" + pubfun.strPoint(it.begin().value().xy) + "-" + pubfun.strPoint(it.end().value().xy));
                        List<int>[] xyzset = new List<int>[9];
                        for (int i = 0; i < 9; ++i)
                        {
                            List<int> li = new List<int>();
                            foreach (int cand in it[i].candidates())
                                li.Add(cand);
                            xyzset[i] = li;
                        }
                        for (int i = 0; i <= comb.GetUpperBound(0); ++i)
                        {
                            List<int> nl = new List<int>();//记录出现的iterator索引位置
                            List<int> cands = new List<int>();//记录合并的候选数集合
                            bool isok = true;
                            int cnt = 0;
                            for (int j = 0; j <= comb.GetUpperBound(1); ++j)
                            {
                                int id = comb[i, j];
                                nl.Add(id);
                                //Debug.Write(pubfun.strListInt(xyzset[id]) + "+");
                                cnt++;
                                cands = pubfun.combin(cands, xyzset[id]);
                                if (xyzset[id].Count == 0 || xyzset[id].Count > dim || cands.Count > dim)
                                {
                                    isok = false;
                                    break;
                                }
                            }
                            //Debug.WriteLine(" = " + pubfun.strListInt(cands));
                            if (cnt < dim || !isok || cands.Count != dim)
                                continue;
                            //找到数集
                            List<number> subset = new List<number>();
                            List<number> numlsit = new List<number>();
                            foreach (number num in it)
                            {
                                bool isset = false;
                                foreach (int id in nl)
                                {
                                    if (num == it[id])
                                    {
                                        isset = true;
                                        subset.Add(num);
                                        break;
                                    }
                                }
                                if (!isset)
                                {
                                    //不是数集的数格，则检查是否有数集里的候选数
                                    foreach (int nc in cands)
                                    {
                                        if (num[nc - 1] == pubfun.Flag.normal)
                                        {
                                            numlist.Add(num);
                                            break;
                                        }
                                    }
                                }
                            }
                            //Debug.WriteLine("在" + pubfun.strIteratorName(it) + "的数格" + pubfun.strNumbers(subset) + "找到" + dim + "数集");
                            if (numlist.Count > 0)
                            {
                                List<Point> pts = new List<Point>();
                                List<Point> setpts = new List<Point>();
                                foreach (number num in subset)
                                {
                                    pts.Add(num.xy);
                                }
                                foreach (number num in numlist)
                                {
                                    setpts.Add(num.xy);
                                }
                                String str = "在" + pubfun.strPoints(pts) + "发现" + dim + "数集，清除" + pubfun.strPoints(setpts) + "里的候选数" + pubfun.strListInt(cands);
                                if (showdebuginfo) Debug.WriteLine(str);
                                operation op = new operation(helper, operation.opname.set_candidate_none, setpts.ToArray(), cands.ToArray(), str);
                                op.tip_itor = new List<iterator>();
                                op.tip_itor.Add(it);
                                op.tip_points = pts;
                                ops.Add(op);
                                if (isSingleStep) return;
                            }
                        }
                    }
                }
            }
        }

        //隐式三数集法 (Hidden Triplet)
        //隐式四数集法 (Hidden Quad) 
        void helper_HiddenNumberSet(List<operation> ops)
        {
            if (ops.Count > 0)//如果已经有解，则不进一步处理
                return;
            operation.SolveHelper helper = operation.SolveHelper.HiddenPair;
            if (showdebuginfo) Debug.WriteLine("隐式数集法(隐式数对法、三数法、四数法)");
            int[] dims = new int[] { 2, 3, 4 };
            foreach (int dim in dims)
            {
                int[,] comb = null;
                switch (dim)
                {
                    case 2:
                        helper = operation.SolveHelper.HiddenPair;
                        comb = pubfun.comb2;
                        break;
                    case 3:
                        helper = operation.SolveHelper.HiddenTriple;
                        comb = pubfun.comb3;
                        break;
                    case 4:
                        helper = operation.SolveHelper.NakedQuad;
                        comb = pubfun.comb4;
                        break;
                }
                for (int loop = 1; loop <= 9; ++loop)
                {
                    if (showdebuginfo) Debug.WriteLine("第" + loop + "轮循环处理，dim=" + dim);
                    Point p1 = new Point(loop, 1);
                    Point p2 = new Point(1, loop);
                    Point p3 = pubfun.basepoints[loop - 1];
                    iterator[] its = new iterator[] { new iteratorX(pz.m_numbers, p2), new iteratorY(pz.m_numbers, p1), new iteratorZ(pz.m_numbers, p3), };
                    foreach (iterator it in its)
                    {
                        List<int>[] poslist = new List<int>[9];
                        for (int i = 0; i < 9; ++i)
                        {
                            poslist[i] = new List<int>();
                            for (int pos = 0; pos < 9; ++pos)
                            {
                                if (it[pos][i] == pubfun.Flag.normal)
                                    poslist[i].Add(pos);
                            }
                            //Debug.WriteLine(pubfun.strIteratorName(it) + "的候选数" + (i + 1) + "出现在" + pubfun.strListInt(poslist[i]));
                        }
                        for (int i = 0; i <= comb.GetUpperBound(0); ++i)
                        {
                            bool isok = true;
                            List<int> pl = new List<int>();
                            List<int> nl = new List<int>();
                            int cnt = 0;
                            for (int j = 0; j <= comb.GetUpperBound(1); ++j)
                            {
                                int id = comb[i, j];
                                nl.Add(id + 1);
                                cnt++;
                                pl = pubfun.combin(pl, poslist[id]);
                                //Debug.Write(pubfun.strListInt(poslist[id]) + "+");
                                if (poslist[id].Count == 0 || poslist[id].Count > dim || pl.Count > dim)
                                {
                                    isok = false;
                                    break;
                                }
                            }
                            //Debug.WriteLine(" = " + pubfun.strListInt(pl));
                            if (cnt < dim || !isok || pl.Count != dim)
                                continue;
                            //此时nl记录了候选数，pl记录的就是候选数所在的数格下标
                            List<Point> pts = new List<Point>();
                            isok = false;
                            foreach (int pos in pl)
                            {
                                pts.Add(it[pos].xy);
                                if (!isok)
                                {
                                    //检查是否有需要删除的候选数
                                    List<int> cl = new List<int>();
                                    cl = pubfun.combin(cl, nl);
                                    cl = pubfun.combin(cl, it[pos].candidates());
                                    isok = (cl.Count > dim);
                                }
                            }
                            if (isok)
                            {
                                //找到隐式数集！且有排除结果
                                String strfind = pubfun.strIteratorName(it) + "在数格" + pubfun.strPoints(pts) + "找到隐式数集" + pubfun.strListInt(nl);
                                List<int> excands = new List<int>();
                                for (int cand = 1; cand <= 9; ++cand)
                                    excands.Add(cand);
                                foreach (int cand in nl)
                                {
                                    excands.Remove(cand);
                                }
                                String str = strfind + "排除候选数" + pubfun.strListInt(excands);
                                if (showdebuginfo) Debug.WriteLine(str);
                                operation op = new operation(helper, operation.opname.set_candidate_none, pts.ToArray(), excands.ToArray(), str);
                                op.tip_itor = new List<iterator>();
                                op.tip_itor.Add(it);
                                op.tip_points = pts;
                                op.tip_number = excands;
                                ops.Add(op);
                                if (isSingleStep) return;
                            }
                        }
                    }
                }
            }

        }


        //X-Wing,SwordFish,JellyFish
        /*
         * 对每个候选数，求出其在每行/列出现的列/行位置，一共得到9个数集
         * 对于9个数字，分别2，3，4个组合，如果得到的数集里的候选数也是2，3，4就表示找到相应的Fish
         * */


        void helper_Fish(List<operation> ops)
        {
            if (ops.Count > 0)
                return;
            if (showdebuginfo) Debug.WriteLine("Searching Fish...");
            for (int cand = 1; cand <= 9; ++cand)
            {
                if (showdebuginfo) Debug.WriteLine("开始查找候选数" + cand);
                List<int>[] xset = new List<int>[9];
                List<int>[] yset = new List<int>[9];
                for (int i = 0; i < 9; ++i)//要分别针对每行/每列进行候选数查找
                {
                    iterator it = (new iteratorX(nums, new Point(1, i + 1)));
                    iterator ity = (new iteratorY(nums, new Point(i + 1, 1)));
                    xset[i] = new List<int>();
                    yset[i] = new List<int>();
                    for (int pos = 1; pos <= 9; ++pos)//找出有cand的位置并记录
                    {
                        if (it[pos - 1][cand - 1] == pubfun.Flag.normal)
                            xset[i].Add(pos);
                        if (ity[pos - 1][cand - 1] == pubfun.Flag.normal)
                            yset[i].Add(pos);
                    }
                }
                //开始查找数集
                List<int[,]> combs = new List<int[,]>();
                combs.Add(pubfun.comb2);//注意顺序！
                combs.Add(pubfun.comb3);
                combs.Add(pubfun.comb4);
                operation.SolveHelper helper = operation.SolveHelper.X_Wing;
                foreach (int dim in new int[] { 2, 3, 4 })
                {
                    foreach (int xy in new int[] { 0, 1 })
                    {
                        switch (dim)
                        {
                            case 2: helper = operation.SolveHelper.X_Wing; break;
                            case 3: helper = operation.SolveHelper.SwordFish; break;
                            case 4: helper = operation.SolveHelper.JellyFish; break;
                        }
                        int[,] comb = combs[dim - 2];
                        for (int i = 0; i <= comb.GetUpperBound(0); ++i)
                        {
                            List<int> nl = new List<int>();//记录cand出现的列
                            List<int> rl = new List<int>();//记录cand出现的行
                            bool isok = true;
                            int cnt = 0;
                            for (int j = 0; j <= comb.GetUpperBound(1); ++j)
                            {
                                int id = comb[i, j];
                                rl.Add(id + 1);
                                List<int> xyset = (xy == 0) ? xset[id] : yset[id];
                                if (showdebuginfo) Debug.Write(pubfun.strListInt(xyset) + "+");
                                nl = pubfun.combin(nl, xyset);
                                ++cnt;
                                if (xyset.Count == 0 || xyset.Count > dim || nl.Count > dim)
                                {
                                    isok = false;
                                    break;
                                }
                            }
                            if (showdebuginfo) Debug.Write(" = " + pubfun.strListInt(nl));
                            if (!isok || cnt <= 1 || nl.Count != dim)
                            {
                                if (showdebuginfo) Debug.WriteLine(" => isok=" + isok + "       cand=" + cand + " dim=" + dim + " nl.Count=" + nl.Count + " cnt=" + cnt);
                                continue;
                            }
                            //发现合适的形状（根据dim不同，分别是X-Wing,SwordFish,JellyFish）
                            //nl记录的就是cand存在的位置，所相关的列需要抹去cand
                            if (showdebuginfo) Debug.WriteLine(" => 在" + (xy == 0 ? "行" : "列") + pubfun.strListInt(rl) + " 发现 " + dim + " 数集 cand=" + cand);
                            List<number> numlist = new List<number>();
                            List<number> fish = new List<number>();
                            List<iterator> its = new List<iterator>();
                            foreach (int n in nl)
                            {
                                if (xy == 0)
                                    its.Add(new iteratorY(nums, new Point(n, 1)));//遍历第n列
                                else
                                    its.Add(new iteratorX(nums, new Point(1, n)));//遍历第n行
                            }
                            foreach (iterator it in its)
                            {
                                //遍历3列的每个包含cand的数格
                                foreach (number num in it)
                                {
                                    if (num[cand - 1] == pubfun.Flag.normal)
                                    {
                                        //还必须不在Fish里
                                        bool inl = false;
                                        int nxy = (xy == 0) ? num.xy.Y : num.xy.X;
                                        foreach (int n in rl)
                                        {
                                            if (n == nxy)
                                            {
                                                inl = true;
                                                break;
                                            }
                                        }
                                        if (!inl)
                                        {
                                            numlist.Add(num);
                                        }
                                    }

                                }
                            }
                            if (numlist.Count > 0)
                            {
                                //找到了因为Fish要排除的数格
                                List<Point> ps = new List<Point>();
                                List<Point> fps = new List<Point>();
                                if (xy == 0)
                                {
                                    foreach (int y in rl)
                                    {
                                        foreach (int x in nl)
                                        {
                                            if (nums[x - 1, y - 1][cand - 1] == pubfun.Flag.normal)
                                            {
                                                fps.Add(new Point(x, y));
                                            }
                                        }
                                    }
                                }
                                else
                                {
                                    foreach (int x in rl)
                                    {
                                        foreach (int y in nl)
                                        {
                                            if (nums[x - 1, y - 1][cand - 1] == pubfun.Flag.normal)
                                            {
                                                fps.Add(new Point(x, y));
                                            }
                                        }
                                    }
                                }
                                foreach (number num in numlist)
                                {
                                    ps.Add(num.xy);
                                }
                                String str = "找到了" + helper.ToString() + ((xy == 0) ? "横向" : "纵向") + "(dim=" + dim + ",cand=" + cand + ")[" + pubfun.strPoints(fps) + "]" + "排除" + pubfun.strPoints(ps) + "的候选数" + cand;
                                if (showdebuginfo)
                                    Debug.WriteLine(str);
                                operation op = new operation(helper, operation.opname.set_candidate_none, ps.ToArray(), new int[] { cand }, str);
                                op.tip_points = fps;
                                op.tip_number = new List<int>();
                                op.tip_number.Add(xy);
                                ops.Add(op);
                                if (isSingleStep) return;
                            }
                        }
                    }
                }
            }
        }


        //XYZ形态匹配法(XYZ-wing) 
        /*
         * 对于某一个三候选数的数格XYZ，如果同方块里有另外一个数格含有其中两个候选数（XY,YZ,XZ）
         * 同时倘若在该三候选数格的行或列发现了（{XZ,YZ}，{XY,XZ}，{XY,YZ}），且发现的数格不在方块内，那么该行在方块内不会有（{X,Y}，{Y,Z}，{X,Z}）
         */
        void helper_XYZ_Wing(List<operation> ops)
        {
            if (ops.Count > 0)
                return;
            operation.SolveHelper helper = operation.SolveHelper.XYZ_Wing;
            if (showdebuginfo) Debug.WriteLine("XYZ-Wing排除法");
            foreach (number numxyz in nums)
            {
                int[] xyzcands = numxyz.candidates();
                if (xyzcands.Length != 3)
                    continue;
                iteratorZ itz = new iteratorZ(nums, numxyz.xy);
                foreach (number numyz in itz)
                {
                    if (numyz.xy != numxyz.xy)
                    {
                        //在itz里找出yz
                        int[] yzcands = numyz.candidates();
                        if (yzcands.Length != 2)
                            continue;
                        int ce = 0;//相等数
                        int[] xyz = new int[] { 0, 0, 0 };
                        for (int i = 0; i < 3; ++i)
                        {
                            int cand = xyzcands[i];
                            if (numxyz[cand - 1] == numyz[cand - 1])
                            {
                                xyz[ce] = cand;
                                ++ce;
                            }
                            else
                                xyz[2] = cand;//最后一个记录不等数
                        }
                        if (ce != 2)
                            continue;
                        //在xyz的行列里寻找xy,xz
                        //需要保持xy,xz有序
                        int[] xy = (xyz[0] < xyz[2]) ? (new int[] { xyz[0], xyz[2] }) : (new int[] { xyz[2], xyz[0] });
                        int[] xz = (xyz[0] < xyz[2]) ? (new int[] { xyz[0], xyz[2] }) : (new int[] { xyz[2], xyz[0] });
                        iterator[] itxys = new iterator[] { new iteratorX(nums, numxyz.xy), new iteratorY(nums, numxyz.xy) };

                        foreach (iterator itxy in itxys)
                        {
                            foreach (number numxz in itxy)
                            {
                                if (pubfun.isSameBlock(numxz.xy, numxyz.xy))
                                    continue;
                                if (numxz.candidates().Length != 2)
                                    continue;
                                //是否找到匹配的数格，如果找到，确定将去除的候选数
                                int cand = 0;
                                if (numxz[xy[0] - 1] == pubfun.Flag.normal && numxz[xy[1] - 1] == pubfun.Flag.normal)
                                {
                                    cand = (xy[0] == xyz[2]) ? xy[1] : xy[0];
                                }
                                else if (numxz[xz[0] - 1] == pubfun.Flag.normal && numxz[xz[1] - 1] == pubfun.Flag.normal)
                                {
                                    cand = (xz[0] == xyz[2]) ? xz[1] : xz[0];
                                }
                                else continue;
                                //在itz里排除与numxyz,numxz同行/列的数格里的候选数cand
                                List<Point> lps = new List<Point>();
                                foreach (number num in itz)
                                {
                                    if (num.xy == numxyz.xy || num.xy == numyz.xy)
                                        continue;
                                    if ((numxyz.xy.X == numxz.xy.X && num.xy.X == numxyz.xy.X) || (numxyz.xy.Y == numxz.xy.Y && num.xy.Y == numxyz.xy.Y))
                                    {
                                        if (num[cand - 1] == pubfun.Flag.normal)
                                            lps.Add(num.xy);
                                    }
                                }
                                if (lps.Count > 0)
                                {
                                    String str = "找到XYZ-Wing数格" + pubfun.strPoints(new Point[] { numxyz.xy, numyz.xy, numxz.xy }) + "，将从数格" + pubfun.strPoints(lps) + "里排除候选数" + cand;
                                    if (showdebuginfo) Debug.WriteLine(str);
                                    operation op = new operation(helper, operation.opname.set_candidate_none, lps.ToArray(), new int[] { cand }, str);
                                    op.tip_itor = new List<iterator>();
                                    op.tip_itor.Add(itz);
                                    op.tip_points = new List<Point>();
                                    op.tip_points.Add(numxyz.xy);
                                    op.tip_points.Add(numyz.xy);
                                    op.tip_points.Add(numxz.xy);
                                    ops.Add(op);
                                    if (isSingleStep) return;
                                }
                            }
                        }
                    }
                }
            }
        }

        //Bug+1解法
        void helper_bug_1(List<operation> ops)
        {
            if (ops.Count > 0)
                return;
            operation.SolveHelper helper = operation.SolveHelper.BUG1;
            if (showdebuginfo) Debug.WriteLine("Bug+1排除法");
            bool hasxyz = false;
            Point xy = new Point(0, 0);
            foreach (number numxyz in nums)
            {
                int[] xyzcands = numxyz.candidates();
                if (xyzcands.Length > 3)
                {
                    return;//超过3个候选数，不适用bug+1
                }
                if (xyzcands.Length == 3)
                {
                    if (hasxyz)
                        return;//多个xyz，不适用bug+1
                    hasxyz = true;
                    xy = numxyz.xy;
                    continue;
                }
            }
            if (!hasxyz)
                return;
            //找到bug+1
            int[] cands = nums[xy.X - 1, xy.Y - 1].candidates();
            iteratorX itx = new iteratorX(nums, xy);
            foreach (int cand in cands)
            {
                int cnt = 0;
                foreach (number num in itx)
                {
                    if (num[cand - 1] == pubfun.Flag.normal)
                    {
                        cnt++;
                    }
                }
                if (cnt == 3)
                {
                    String str = "找到BUG+1数格，" + pubfun.strPoint(xy) + "=" + cand;
                    operation op = new operation(helper, operation.opname.set_number, new Point[] { xy }, new int[] { cand }, str);
                    op.tip_points = new List<Point>();
                    op.tip_points.Add(xy);
                    op.tip_number = new List<int>();
                    op.tip_number.Add(cand);
                    ops.Add(op);
                }
            }
        }

        private Random rand = new Random();
        private String _strResult = "";
        public String strResult
        {
            get { return _strResult; }
            set
            {
                String str = value.Replace("\r\n", "");
                if (str.Length != 81)
                    return;
                _strResult = str;
            }
        }
        public int this[int x, int y]
        {
            get
            {
                if (!pubfun.isValidValue(x) || !pubfun.isValidValue(y))
                    return -1;
                return _strResult.ToCharArray()[(y - 1) * 9 + x - 1] - '0';
            }
            set
            {
                if (!pubfun.isValidValue(x) || !pubfun.isValidValue(y))
                    return;
                if (_strResult.Length != 81)
                    return;
                Char[] chs = _strResult.ToCharArray();
                chs[(y - 1) * 9 + x - 1] = (Char)('0' + value);
                StringBuilder sb = new StringBuilder();
                foreach (Char ch in chs)
                {
                    sb.Append(ch);
                }
                _strResult = sb.ToString();
            }
        }
        void helper_Guess(List<operation> ops)
        {
            if (ops.Count > 0)
                return;
            operation.SolveHelper helper = operation.SolveHelper.Guess;
            if (showdebuginfo) Debug.WriteLine("猜数法");
            if (_strResult.Length == 81)
            {
                //如果已经有终局，就不去递归查找了
                foreach (number nn in nums)
                {
                    if (nn.candidates().Length == 2)//很难见到没有两位候选数的情况，所以只对候选数为2的数格进行处理就够了
                    {
                        String str = "假设" + pubfun.strPoint(nn.xy) + "为" + this[nn.xy.X, nn.xy.Y] + "，可以推导出答案！";
                        if (showdebuginfo) Debug.WriteLine(str);
                        operation op = new operation(helper, operation.opname.set_number, new Point[] { nn.xy }, new int[] { this[nn.xy.X, nn.xy.Y] }, str);
                        ops.Add(op);
                        return;
                    }
                }
            }
            number num = nums[0, 0];
            int c = 0;
            while (true && c++ < 100)
            {
                int r = rand.Next(1, 81);
                num = nums[(r - 1) / 9, (r - 1) % 9];
                if (num.value == 0 && num.candidates().Length > 0)
                    break;
            }
            //foreach(number num in nums)
            {
                if (num.candidates().Length > 0)
                {
                    Hashtable candright = new Hashtable();
                    Hashtable candwrong = new Hashtable();
                    foreach (int cand in num.candidates())
                    {
                        //必须要深层复制，否则递归步骤相互干扰
                        puzzle newpz = new puzzle();
                        newpz.loadPuzzle(pz.exportPuzzle().ToCharArray());

                        if (showdebuginfo) Debug.WriteLine("假设" + pubfun.strNumber(num) + "选择候选数" + cand);
                        newpz[num.xy] = cand;
                        solver new_solver = new solver(newpz);
                        bool ret = true;
                        while (ret)
                        {
                            ret = new_solver.run(1);//点一次执行一步
                            if (!new_solver.single_solution)
                            {
                                single_solution = false;
                                return;
                            }
                        }
                        puzzle.Status st = newpz.getPuzzleStatus();
                        if (st == puzzle.Status.SUCCESS)
                        {
                            candright[cand] = new_solver;
                            if (!new_solver.single_solution || candright.Count > 1)//是否唯一解
                            {
                                single_solution = false;
                                break;
                            }
                        }
                        else //if (st == puzzle.Status.ERROR)
                        {
                            candwrong[cand] = new_solver;
                            //no,the number is not ok!
                        }
                    }
                    if (candright.Count > 0)
                    {
                        List<solver> new_solvers = new List<solver>();
                        List<int> cands = new List<int>();
                        foreach (DictionaryEntry de in candright)
                        {
                            cands.Add((int)de.Key);
                            new_solvers.Add((solver)de.Value);
                        }
                        {
                            String str = "假设" + pubfun.strPoint(num.xy) + "为" + pubfun.strListInt(cands) + "，可以推导出答案！";
                            if (showdebuginfo) Debug.WriteLine(str);
                            operation op = new operation(helper, operation.opname.set_number, new Point[] { num.xy }, cands.ToArray(), str);
                            ops.Add(op);
                            //foreach (operation rop in new_solvers[0].ops)
                            //{
                            //    ops.Add(rop);
                            //}
                        }
                    }
                    else
                    {
                        List<int> cands = new List<int>();
                        foreach (DictionaryEntry de in candwrong)
                        {
                            int cand = (int)de.Key;
                            cands.Add(cand);
                        }
                        {
                            String str = "假设" + pubfun.strPoint(num.xy) + "为" + pubfun.strListInt(cands) + "，无法推导出答案！";
                            if (showdebuginfo) Debug.WriteLine(str);
                            operation op = new operation(helper, operation.opname.set_candidate_none, new Point[] { num.xy }, cands.ToArray(), str);
                            ops.Add(op);
                        }

                    }
                }
            }
        }

        //需要保持链表的顺序！可指定从哪个节点开始输出
        private String dump_chain(List<int[]> chain, int[] head)
        {
            StringBuilder sb = new StringBuilder();
            bool dump = false;
            for (int i = 0; i < chain.Count; ++i)
            {
                int[] node = chain[i];
                if (head != null)
                {
                    if (pubfun.is_same_chain_node(head, node))
                        dump = true;
                    if (!dump)
                        continue;
                }
                Point p = new Point(node[0], node[1]);
                int cand = node[2];
                sb.Append("[");
                sb.Append(pubfun.strPoint(p));
                sb.Append("_" + cand + "]");
                if (node[3] > 0)
                {
                    sb.Append(" = ");
                }
                else
                {
                    sb.Append(" - ");
                }
            }
            return sb.ToString();
        }
        private String dump_inference(List<int[]> chain, int[] head)
        {
            StringBuilder sb = new StringBuilder();
            bool dump = false;
            int head_index = 0;
            for (int i = 0; i < chain.Count; ++i)
            {
                int[] node = chain[i];
                if (pubfun.is_same_chain_node(head, node))
                {
                    dump = true;
                    head_index = i;
                }
                if (!dump)
                    continue;
                Point p = new Point(node[0], node[1]);
                int cand = node[2];
                sb.Append(pubfun.strPoint(p));
                sb.Append((node[3] == 1) ? "!=" : "=");
                sb.Append(+cand);
                sb.Append((node[3] == 1) ? " => " : " -> ");
            }
            sb.Append(pubfun.strPoint(new Point(head[0], head[1])));
            sb.Append(chain[head_index][3] == 1 ? "=" : "!=");
            sb.Append(head[2]);
            return sb.ToString();
        }
        private int[] get_chain_node(List<int[]> chain, int[] node)
        {
            foreach (int[] n1 in chain)
            {
                if (pubfun.is_same_chain_node(n1, node))
                {
                    return n1;
                }
            }
            return null;
        }
        public class chain_node
        {
            public Point p;
            public int cand;
            public chain_node()
            {
                strong_nodes = new List<int[]>();
                weak_nodes = new List<int[]>();
            }
            public List<int[]> strong_nodes;
            public List<int[]> weak_nodes;
            public bool add_weak_node(int[] node)
            {
                if (node.Length < 3)
                    return false;
                foreach (int[] nl in weak_nodes)
                {
                    if (nl[0] == node[0] && nl[1] == node[1] && nl[2] == node[2])
                        return false;
                }
                weak_nodes.Add(node);
                return true;
            }
            public bool add_strong_node(int[] node)
            {
                if (node.Length < 3)
                    return false;
                foreach (int[] nl in strong_nodes)
                {
                    if (nl[0] == node[0] && nl[1] == node[1] && nl[2] == node[2])
                        return false;
                }
                strong_nodes.Add(node);
                return true;
            }
        }
        private chain_node[, ,] nodes = new chain_node[10, 10, 10];
        //默认处理所有可能的强链弱链
        //对于X-Chain只处理指定候选数的连接
        //对于XY-Chain只处理在当前节点找强连接，在其他节点只找弱连接
        private chain_node build_Forcing_Node(operation.SolveHelper helper, int x, int y, int cand, int link_type)
        {
            chain_node node = nodes[x, y, cand];
            if (node != null)
                return node;

            number num = nums[x - 1, y - 1];
            node = new chain_node();
            nodes[x, y, cand] = node;
            node.p = num.xy;
            node.cand = cand;
            nodes[node.p.X, node.p.Y, cand] = node;

            bool link_strong_to_add = (link_type == 0 || link_type == 1);
            bool link_weak_to_add = (link_type == 0 || link_type == 2);

            //搜索强连接和弱连接的节点
            iterator[] its = new iterator[] { new iteratorZ(nums, node.p), new iteratorX(nums, node.p), new iteratorY(nums, node.p), };
            foreach (iterator it in its)
            {
                List<number> numlist = new List<number>();
                foreach (number n in it)
                {
                    if (n.xy == node.p)//不在这里处理自身
                        continue;
                    if (n[cand - 1] == pubfun.Flag.normal)
                    {
                        numlist.Add(n);
                    }
                }
                if (numlist.Count == 1)//找到强连接
                {
                    int[] link = new int[] { numlist[0].xy.X, numlist[0].xy.Y, cand };
                    if (link_strong_to_add && helper != operation.SolveHelper.XY_Chain)
                        node.add_strong_node(link);
                    if (link_weak_to_add) //强连接也要归到弱连接里
                        node.add_weak_node(link);
                }
                else
                {
                    //都是弱连接
                    foreach (number n in numlist)
                    {
                        int[] link = new int[] { n.xy.X, n.xy.Y, cand };
                        node.add_weak_node(link);
                    }
                }
            }
            if (helper == operation.SolveHelper.X_Chain)
                return node;//X-Chain不需要考虑节点的其他候选数

            //单独处理一下node.p的其他候选数
            int[] cands = num.candidates();
            if (cands.Length == 2)
            {
                foreach (int nc in cands)
                {
                    int[] link = new int[] { node.p.X, node.p.Y, nc };
                    if (nc != cand)
                    {
                        if (link_strong_to_add)
                            node.add_strong_node(link);
                        if (link_weak_to_add && helper != operation.SolveHelper.XY_Chain)
                            node.add_weak_node(link);
                    }
                }
            }
            else
            {
                if (helper != operation.SolveHelper.XY_Chain)
                {
                    //XY-Chain只处理两个候选数的节点
                    foreach (int nc in cands)
                    {
                        if (nc != cand)
                            node.add_weak_node(new int[] { node.p.X, node.p.Y, nc });
                    }
                }
            }
            return node;
        }
        private bool find_chain(operation.SolveHelper helper, List<int[]> chain, int recur, Point p, int cand, List<operation> ops, bool bFindStrongLink)
        {
            if (recur > max_recurise) //过长的链就不去考虑了
                return false;

            //将p放到链里，p是当前接节点，bFindStrongLink表示是否是强链的头
            iterator[] its = new iterator[] { new iteratorX(nums, p), new iteratorY(nums, p), new iteratorZ(nums, p) };

            int[] node = new int[] { p.X, p.Y, cand, bFindStrongLink ? 1 : 0 };
            int[] pnode = new int[4];//将当前节点添加到链里
            chain.Add(node);


            if (showdebuginfo)
                Debug.WriteLine("添加当前节点：" + dump_chain(chain, null));

            if (chain.Count > 1)
            {
                pnode = chain[chain.Count - 2];//取出当前node节点前一个节点
            }
            chain_node cn = build_Forcing_Node(helper, p.X, p.Y, cand, 0);
            if (bFindStrongLink) //找强链
            {
                foreach (int[] xyz in cn.strong_nodes)
                {
                    int[] np = new int[] { xyz[0], xyz[1], xyz[2], 0 };
                    if (helper == operation.SolveHelper.X_Chain && xyz[2] != cand) //X_Chain链和单链只寻找单候选数
                        continue;
                    if (pnode != null && pubfun.is_same_chain_node(pnode, np)) //跳过父节点
                        continue;
                    int[] fnode = get_chain_node(chain, np);//是否已经遍历过该节点
                    Point pp = new Point(np[0], np[1]);
                    if (fnode != null)
                    {
                        //检查是否可以得到推论1 （强链头与强链头存在强链）
                        if (fnode[3] == 1)
                        {
                            if (showdebuginfo) Debug.WriteLine("找到一个矛盾链：" + dump_chain(chain, np));
                            String str = helper.ToString() + "假设" + dump_inference(chain, np) + "所以" + pubfun.strPoint(pp) + "=" + np[2];
                            if (showdebuginfo) Debug.WriteLine(str);
                            operation op = new operation(helper, operation.opname.set_number, new Point[] { pp }, new int[] { np[2] }, str);
                            op.tip_chain = chain;
                            op.tip_chain_head = np;
                            ops.Add(op);
                            return true;
                        }
                    }
                    else
                    {
                        //递归找下一个节点，如果找不到，则继续找其他的强链
                        if (find_chain(helper, chain, recur + 1, pp, np[2], ops, false))
                            return true;
                    }
                }
            }
            else //找弱链
            {
                foreach (int[] xyz in cn.weak_nodes)
                {
                    int[] np = new int[] { xyz[0], xyz[1], xyz[2], 1 };
                    if (helper == operation.SolveHelper.X_Chain && xyz[2] != cand)//X_Chain链只寻找单候选数
                        continue;
                    if (pnode != null && pubfun.is_same_chain_node(pnode, np)) //跳过父节点
                        continue;
                    int[] fnode = get_chain_node(chain, np);//是否已经遍历过该节点
                    Point pp = new Point(np[0], np[1]);
                    if (fnode != null)
                    {
                        if (fnode[3] == 0)
                        {
                            if (showdebuginfo) Debug.WriteLine("找到一个矛盾链：" + dump_chain(chain, np));
                            String str = helper.ToString() + "假设" + dump_inference(chain, np) + "所以" + pubfun.strPoint(pp) + "!=" + np[2];
                            if (showdebuginfo) Debug.WriteLine(str);
                            operation op = new operation(helper, operation.opname.set_candidate_none, new Point[] { pp }, new int[] { np[2] }, str);
                            op.tip_chain = chain;
                            op.tip_chain_head = np;
                            ops.Add(op);
                            return true;
                        }
                    }
                    else
                    {
                        //递归找下一个节点，如果找不到，则继续找其他的强链
                        if (find_chain(helper, chain, recur + 1, pp, np[2], ops, true))
                            return true;
                    }

                }
            }
            //因为找不到后续的节点，当前节点也应该抹去
            node = chain[chain.Count - 1];
            chain.RemoveAt(chain.Count - 1);
            if (showdebuginfo) Debug.WriteLine("移除当前节点:" + dump_chain(chain, null));

            return false;
        }
        void helper_Forcing_Chain(List<operation> ops)
        {
            if (ops.Count > 0)
                return;
            operation.SolveHelper helper = operation.SolveHelper.Forcing_Chain;
            if (showdebuginfo) Debug.WriteLine("Forcing_Chain");
            nodes = new chain_node[10, 10, 10];
            foreach (number num in nums)
            {
                foreach (int cand in num.candidates())
                {
                    //showdebuginfo = (num.xy == new Point(2, 7) && cand == 2);//跟踪C2=2开头的链
                    //if (num.xy == new Point(2, 7) && cand == 2)
                    //    showdebuginfo = true;
                    //else
                    //    showdebuginfo = false;
                    Hashtable ht = new Hashtable();
                    List<int[]> chain = new List<int[]>();
                    if (find_chain(helper, chain, 1, num.xy, cand, ops, true))
                        return;
                    if (find_chain(helper, chain, 1, num.xy, cand, ops, false))//从弱链开始也可以！
                        return;
                }
            }
        }
        void helper_X_Chain(List<operation> ops)
        {
            if (ops.Count > 0)
                return;
            operation.SolveHelper helper = operation.SolveHelper.X_Chain;
            //showdebuginfo = true;
            if (showdebuginfo) Debug.WriteLine("X_Chain");
            nodes = new chain_node[10, 10, 10];
            foreach (number num in nums)
            {
                foreach (int cand in num.candidates())
                {
                    List<int[]> chain = new List<int[]>();
                    if (find_chain(helper, chain, 1, num.xy, cand, ops, true))
                        return;
                    if (find_chain(helper, chain, 1, num.xy, cand, ops, false))
                        return;
                }
            }
        }

        void helper_XY_Chain(List<operation> ops)
        {
            if (ops.Count > 0)
                return;
            operation.SolveHelper helper = operation.SolveHelper.XY_Chain;
            //showdebuginfo = true;
            if (showdebuginfo) Debug.WriteLine("XY_Chain");
            nodes = new chain_node[10, 10, 10];
            foreach (number num in nums)
            {
                //if (num.candidates().Length != 2)
                //    continue;
                foreach (int cand in num.candidates())
                {
                    List<int[]> chain = new List<int[]>();
                    if (find_chain(helper, chain, 1, num.xy, cand, ops, false))
                        return;
                }
            }
        }

        bool is_strong_link(number na, number nb, int cand, ref iterator itout)
        {
            iterator[] its = new iterator[] { new iteratorX(nums, na.xy), new iteratorY(nums, na.xy), new iteratorZ(nums, na.xy), };
            foreach (iterator it in its)
            {
                if (it.ContainPoint(nb.xy) && pubfun.get_cand_pos(it, cand).Count == 2)
                {
                    itout = it;
                    return true;
                }
            }
            return false;
        }

        //这个函数未了解完全就开始编写，太多冗余代码了
        void helper_UniqueRectangle(List<operation> ops)
        {
            if (ops.Count > 0)
                return;
            foreach (number ltnum in nums)
            {
                if (ltnum.value > 0)
                    continue;
                Point bp = new Point((ltnum.xy.X - 1) / 3 + 1, (ltnum.xy.Y - 1) / 3 + 1);
                for (int x = ltnum.xy.X + 1; x <= 9; ++x)
                {
                    for (int y = ltnum.xy.Y + 1; y <= 9; ++y)
                    {
                        //if (ltnum.xy.X == 5 && ltnum.xy.Y == 2 && x==6 && y==7)
                        //    Debug.Write("Debug\r\n");
                        if ((x - 1) / 3 + 1 == bp.X && (y - 1) / 3 + 1 == bp.Y)
                            continue;//在一个box的矩形不做检查
                        if (nums[x - 1, y - 1].value > 0)
                            continue;
                        //检查是否是UR1
                        List<Point> pts = new List<Point>();
                        //注意添加的顺序：左上，右上，左下，右下！
                        pts.Add(ltnum.xy);
                        pts.Add(new Point(x, ltnum.xy.Y));
                        pts.Add(new Point(ltnum.xy.X, y));
                        pts.Add(new Point(x, y));
                        List<number> numlist = new List<number>();
                        bool isskip = false;
                        List<int> cis = new List<int>();
                        List<int> cmb = new List<int>();
                        foreach (Point pt in pts)
                        {
                            number num = nums[pt.X - 1, pt.Y - 1];
                            if (num.value > 0)
                            {
                                isskip = true;
                                break;
                            }
                            numlist.Add(num);
                            int[] cands = num.candidates();
                            cmb = pubfun.combin(cmb, cands);
                            if (cis.Count == 0)//第一次初始化
                                cis = cmb;
                            cis = pubfun.intersection_int(cis, cands);

                            if (cis.Count < 2)
                            {
                                isskip = true;
                                break;
                            }
                        }
                        if (isskip)
                            continue;
                        //对解法有疑问时，访问下面的地址以确认：
                        //http://www.sudocue.net/guide.php#UniqueCorner
                        //http://www.sudopedia.org/wiki/Solving_Technique

                        //UR1组成矩形的四个方块内，都由候选数xy组成，但是其中一个多了一个一个候选数z，则该数格就必然是z。
                        //UR2由xy组成的矩形上，倘若在其中两个数格还都有另外一个候选数z，则这两个数格必有其中一个为z，所以在这两个数格所在的house(行/列/块)里必定不能再出现z 
                        //UR3跟UR2类似，但是这两个数格内不是同一个候选数，而是候选数a,b。此时可以把这两个数格看做一个只含有候选数a和b的数格，它可以与house内的另外的数格一起组成显式数集，从而排除其他数格里的候选数 
                        //UR4这又是第三种情况的另外一种特例。假设a和b所在行/列里，别的数格里不包含x，则在xya,xyb这两个数格里，必然包含有a或b以及x，所以必然不包含y！ 
                        //UR5有三个是含候选数xyz，只有一个是含候选数xy，并且四个数格是分布在两个宫格（Box）里。此时，对于同时在三个含 z数格的house里的数格，可以排除候选数z。这个推理其实也很简单，因为三个z必然有一个为真（即该格就是数字z），无论哪一个为z，对于可以同时与这三个数格在同一个house的数格（最多两个，与其中两个z在一个box内） 
                        //UR6要求四个格都含有xy，且其中在两行两列上x只出现在这两个数格里，且在四个方格的存在对角是xy的情况，则另外两个对角比如不是x。
                        //UR7假设我们有一个A,B,C,D数格组成的矩形，A和D在对角，B和C在对角，且AB或BD在同一个BOX里，且他们各自的候选数满足这样的情况： A为ab，B为abx，C为aby，D为abz，其中x,y表示1个以上的候选数，z表示0个以上的候选数xyz可以存在相同的候选数。假定在B和D共同的house里，候选数a只在B和D出现，C和D的共同的house里，a也只在C和D出现，这个时候我们就可以从D里排除候选数b 
                        if (cis.Count != 2) //候选数交集不是2个，则不是UR
                            continue;

                        //此时pts保存四角数格的坐标，numlist保存的是四角数格的number对象

                        //注意UR6和UR7可能包含在cmb.Count==3的情况里，UR6似乎是UR7的一种特例，即z为无的特例

                        //找有额外候选数的对角数格
                        //如果找到，则判断另外一边是否还有额外候选数，
                        //          如果没有则判断是否存在一个对角某候选数为真就导致对角候选数为真的情况（弱强链），如果有，则排除该候选数
                        //          如果有，则必须要在这个角找到矩形候选数的强链才可以
                        //如果没找到对角数格，则不会是UR6,7
                        number A = numlist[0];
                        number B = numlist[1];
                        number C = numlist[2];
                        number D = numlist[3];
                        bool maybe67 = false;
                        //调整，使得A为两候选数，B,C为对角有额外候选数
                        if (A.candidates().Length > 2 && D.candidates().Length > 2)
                        {
                            maybe67 = true;
                            pubfun.swap(ref A, ref C);
                            pubfun.swap(ref B, ref D);
                        }
                        else if (C.candidates().Length > 2 && B.candidates().Length > 2)
                        {
                            maybe67 = true;
                        }

                        if (A.candidates().Length > 2)
                            pubfun.swap(ref A, ref D);
                        if (A.candidates().Length > 2)
                            continue; //四个单元格都不止2个候选数，不符合矩形排除法
                        if (maybe67)
                        {
                            //此时满足A两位候选数，B和C多余两位候选数
                            iterator it = new iteratorX(nums, D.xy);//随便赋值一个
                            if (D.candidates().Length > 2)
                            {
                                //只有一种链可以达成对角同时为真！CD,BD强！
                                for (int i = 0; i < cis.Count; ++i)
                                {
                                    int cand = cis[i];
                                    int cand_remove = cis[(i + 1) % 2];
                                    iterator itcd = it;
                                    iterator itbd = it;
                                    bool linkcd = is_strong_link(C, D, cand, ref itcd);
                                    bool linkbd = is_strong_link(B, D, cand, ref itbd);

                                    if (linkbd && linkcd)
                                    {
                                        //此时C为真必然导致D为真，且D只能为多余的候选数之一，反之亦然，所以从D排除另外一个候选数
                                        operation.SolveHelper helper = operation.SolveHelper.UniqueRectangle7;
                                        String str = "在唯一矩形" + pubfun.strPoints(pts) + pubfun.strListInt(cis) + "(" + helper.ToString() + ")里，" + cand + "在" + pubfun.strIteratorName(itcd) + "和" + pubfun.strIteratorName(itbd) +
                                            "形成强链，移除" + pubfun.strPoint(D.xy) + "的候选数" + cand_remove;
                                        if (showdebuginfo) Debug.WriteLine(str);
                                        operation op = new operation(helper, operation.opname.set_candidate_none, new Point[] { D.xy }, new int[] { cand_remove }, str);
                                        op.tip_itor = new List<iterator>();
                                        op.tip_itor.Add(itcd);
                                        op.tip_itor.Add(itbd);
                                        op.tip_points = pts;
                                        op.tip_number = cis;
                                        ops.Add(op);
                                        if (isSingleStep) return;
                                    }
                                }
                            }
                            else
                            {
                                //有多种链可以达成对角同时为真！AB和CD强，AC和BD强，或者AB,AC强和CD,BD强，但是AC和CD强或者AB与BD强是不能得出推断的
                                foreach (int cand in cis)
                                {
                                    iterator itab = it, itcd = it, itac = it, itbd = it;
                                    bool linkab = is_strong_link(A, B, cand, ref itab);
                                    bool linkcd = is_strong_link(C, D, cand, ref itcd);
                                    bool linkac = is_strong_link(A, C, cand, ref itac);
                                    bool linkbd = is_strong_link(B, D, cand, ref itbd);

                                    iterator it1 = itab;
                                    iterator it2 = itcd;
                                    bool find = false;
                                    if (linkab && linkcd)
                                        find = true;
                                    else if (linkac && linkbd)
                                    {
                                        find = true;
                                        it1 = itac;
                                        it2 = itbd;
                                    }
                                    else if (linkab && linkac)
                                    {
                                        find = true;
                                        it1 = itab;
                                        it2 = itac;
                                    }
                                    else if (linkbd && linkcd)
                                    {
                                        find = true;
                                        it1 = itbd;
                                        it2 = itcd;
                                    }
                                    if (find)
                                    {
                                        //此时C为真必然导致D为真，所以移除C和D的候选数
                                        Point[] expts = new Point[] { C.xy, B.xy };
                                        operation.SolveHelper helper = operation.SolveHelper.UniqueRectangle6;
                                        String str = "在唯一矩形" + pubfun.strPoints(pts) + pubfun.strListInt(cis) + "(" + helper.ToString() + ")里，" + cand +
                                            "在" + pubfun.strIteratorName(it1) + "和" + pubfun.strIteratorName(it2) +
                                            "形成强链，移除" + pubfun.strPoints(expts) + "的候选数" + cand;
                                        if (showdebuginfo)
                                            Debug.WriteLine(str);
                                        operation op = new operation(helper, operation.opname.set_candidate_none, expts, new int[] { cand }, str);
                                        op.tip_itor = new List<iterator>();
                                        op.tip_itor.Add(it1);
                                        op.tip_itor.Add(it2);
                                        op.tip_points = pts;
                                        op.tip_number = cis;
                                        ops.Add(op);
                                        if (isSingleStep) return;
                                    }
                                }
                            }
                        }
                        if (cmb.Count == 3)//只有一个额外候选数的情况
                        {
                            #region UR1,UR2,UR5
                            //进行UR1
                            //找出几个包含有多余候选数z的数格的group的交集，交集数格也必须要包含有候选数z
                            int cand = 0;
                            foreach (int nc in cmb)
                            {
                                bool find = false;
                                foreach (int ns in cis)
                                {
                                    if (nc == ns)
                                    {
                                        find = true;
                                        break;
                                    }
                                }
                                if (!find)
                                {
                                    cand = nc;//在并集里比交集多的那个数字就是多出来的候选数
                                    break;
                                }
                            }
                            //此时cand即为多出的那个候选数

                            List<number> nzl = null;
                            int cnt = 0;
                            foreach (number num in numlist)
                            {
                                if (num.candidates().Length > 2)
                                {
                                    cnt++;
                                    if (nzl == null)
                                        nzl = pz.get_group(num.xy);
                                    else
                                        nzl = pubfun.numbers_intersection(nzl.ToArray(), pz.get_group(num.xy).ToArray());
                                    //排除nzl里没有包含z的数格
                                    for (int i = nzl.Count - 1; i >= 0; i--)
                                    {
                                        if (nzl[i][cand - 1] != pubfun.Flag.normal)
                                        {
                                            nzl.RemoveAt(i);
                                        }
                                    }
                                }
                            }
                            if (nzl.Count == 0)
                                continue;
                            //nzl里的数格即为可以由UR1,UR2,UR5其中之一排除候选数z，如果cnt为1是UR1，为2是UR2，为3则是UR5
                            operation.SolveHelper helper = new operation.SolveHelper();
                            switch (cnt)
                            {
                                case 1: helper = operation.SolveHelper.UniqueRectangle1; break;
                                case 2: helper = operation.SolveHelper.UniqueRectangle2; break;
                                case 3: helper = operation.SolveHelper.UniqueRectangle5; break;
                                default:
                                    //throw new Exception("错误的唯一矩形!");
                                    continue;//不再做其他的检测了
                            }
                            List<Point> expts = new List<Point>();
                            foreach (number num in numlist)
                            {
                                if (num.candidates().Length > 2)
                                    expts.Add(num.xy);
                            }
                            if (cnt == 1)
                            {
                                //必须判断四个格是否不是处于四个box，如果是，则不是UR1
                                iterator itz = new iteratorZ(nums, A.xy);
                                if (itz.ContainPoint(B.xy) || itz.ContainPoint(C.xy) || itz.ContainPoint(D.xy))
                                {
                                    String str = pubfun.strPoint(expts[0]) + "=" + cand + "：因为唯一矩形" + pubfun.strPoints(pts) + pubfun.strListInt(cis) + "(" + helper.ToString() + ")里只有" + pubfun.strPoint(expts[0]) + "有多余唯一数" + cand + "！";
                                    operation op = new operation(helper, operation.opname.set_number, expts.ToArray(), new int[] { cand }, str);
                                    //传递矩形数格，矩形候选数
                                    op.tip_points = pts;
                                    op.tip_number = cis;
                                    ops.Add(op);
                                    if (isSingleStep) return;
                                }
                            }
                            else
                            {
                                List<Point> fpts = new List<Point>();
                                foreach (number num in nzl)
                                {
                                    fpts.Add(num.xy);
                                }
                                String str = "唯一矩形" + pubfun.strPoints(pts) + pubfun.strListInt(cis) + "(" + helper.ToString() + ")里只有" + pubfun.strPoints(expts) + "有多余唯一数" + cand + "，所以从其可同时看见的数格" + pubfun.strPoints(fpts) + "排除" + cand;
                                operation op = new operation(helper, operation.opname.set_candidate_none, fpts.ToArray(), new int[] { cand }, str);
                                //传递矩形数格，矩形候选数
                                op.tip_points = pts;
                                op.tip_number = cis;
                                ops.Add(op);
                                if (isSingleStep) return;
                            }
                            #endregion UR1,UR2,UR5
                        }
                        if (cmb.Count == 4) //有两个候选数的情况
                        {
                            //UR4
                            //找出额外数格，对于额外数格里的候选数xy，检查是否是所在行/列里
                            //UR3
                            //找出额外数格，然后找group交集，然后找数集，最后找排除数

                            List<Point> expts = new List<Point>();
                            List<Point> fpts = new List<Point>();
                            foreach (number num in numlist)
                            {
                                if (num.candidates().Length > 2)
                                    expts.Add(num.xy);
                                else
                                    fpts.Add(num.xy);
                            }

                            if (expts.Count == 2)
                            {
                                //检测是否是UR4
                                List<iterator> its = new List<iterator>();
                                foreach (iterator it in new iterator[] { new iteratorX(nums, expts[0]), new iteratorY(nums, expts[0]), new iteratorZ(nums, expts[0]), })
                                {
                                    if (it.ContainPoint(expts[1]))
                                    {
                                        its.Add(it);
                                    }
                                }
                                foreach (iterator it in its)
                                {
                                    bool find = false;
                                    int i = -1;
                                    int j = -1;
                                    if (pubfun.get_cand_pos(it, cis[0]).Count == 2)
                                    {
                                        find = true;
                                        i = 0;
                                        j = 1;
                                    }
                                    else if (pubfun.get_cand_pos(it, cis[1]).Count == 2)
                                    {
                                        find = true;
                                        i = 1;
                                        j = 0;
                                    }
                                    if (find && i != -1)
                                    {
                                        //找到UR4
                                        operation.SolveHelper helper = operation.SolveHelper.UniqueRectangle4;
                                        String str = "唯一矩形" + pubfun.strPoints(pts) + pubfun.strListInt(cis) + "(" + helper.ToString() + ")里，" +
                                            pubfun.strPoints(expts) + "的矩形候选数" + cis[i] + "在" + pubfun.strIteratorName(it) + "只出现了两次，所以排除" + pubfun.strPoints(expts) + "里的" + cis[j];
                                        if (showdebuginfo) Debug.WriteLine(str);
                                        operation op = new operation(helper, operation.opname.set_candidate_none, expts.ToArray(), new int[] { cis[j] }, str);
                                        op.tip_points = pts;
                                        op.tip_number = cis;
                                        op.tip_itor = new List<iterator>();
                                        op.tip_itor.Add(it);
                                        ops.Add(op);
                                        if (isSingleStep) return;
                                    }
                                }
                            }

                            //UR3检查找出被expts共同看到的数格，在其中寻找2数集和3数集（显式）
                            //不能使用group的交集，因为可能交集里的数格根本不再一个house里，这种情况是不可以应用数集法的
                            foreach (iterator it in new iterator[] { new iteratorX(nums, expts[0]), new iteratorY(nums, expts[0]), new iteratorZ(nums, expts[0]), })
                            {
                                bool itok = true;
                                for (int i = 1; i < expts.Count; ++i)
                                {
                                    if (!it.ContainPoint(expts[i]))
                                    {
                                        itok = false;
                                        break;
                                    }
                                }
                                if (!itok) continue;

                                List<number> nzl = new List<number>();
                                int cnt = 0;
                                foreach (number num in it)
                                {
                                    if (!pubfun.find(numlist, num))
                                    {
                                        nzl.Add(num);
                                    }
                                }
                                if (nzl.Count < 2) //因为最少也应该可以形成2数集，所以至少要有2个可见方格交集才有必要进行UR3的判断！
                                    continue;
                                //应该可以检查隐式和显式数集，甚至可以结合更多的其他解法，比如Chain，但是从观察多方式而言，显示数集法应该是比较明显的
                                foreach (int dim in new int[] { 2, 3 })
                                {
                                    int[,] comb = pubfun.comb2;
                                    if (dim > nzl.Count)
                                        break;
                                    switch (dim)
                                    {
                                        case 2: comb = new int[,] { { 0, 0 }, { 0, 1 }, { 0, 2 }, { 0, 3 }, { 0, 4 }, { 0, 5 }, { 0, 6 }, { 0, 7 }, { 0, 8 }, }; break;
                                        case 3: comb = pubfun.comb2; break;
                                    }
                                    for (int i = 0; i <= comb.GetUpperBound(0); ++i)
                                    {
                                        List<int> nl = new List<int>();//记录出现的iterator索引位置

                                        //此时nzl里的数格就是将要进行数集检查的数格，找出候选数集合
                                        List<int> cands = new List<int>();
                                        cands.InsertRange(0, cmb);//记录合并的候选数集合
                                        cnt = 1;
                                        foreach (int ab in cis)
                                        {
                                            cands.Remove(ab);
                                        }
                                        bool isok = true;
                                        //Debug.Write(pubfun.strListInt(cands) + "+");
                                        for (int j = 0; j <= comb.GetUpperBound(1); ++j)
                                        {
                                            //如果下标超过nzl，跳过
                                            int id = comb[i, j];
                                            if (id >= nzl.Count)
                                                continue;
                                            //如果是expts里的也跳过
                                            if (pubfun.find(expts, nzl[id].xy))
                                                continue;
                                            nl.Add(id);
                                            cnt++;
                                            int[] tcs = nzl[id].candidates();
                                            cands = pubfun.combin(cands, tcs);
                                            //Debug.Write(pubfun.strListInt(tcs) + "+");
                                            if (tcs.Length == 0 || tcs.Length > dim || cands.Count > dim)
                                            {
                                                isok = false;
                                                break;
                                            }
                                        }
                                        if (nl.Count == 0)
                                            continue;
                                        //Debug.WriteLine(" = " + pubfun.strListInt(cands));
                                        if (cnt < dim || !isok || cands.Count != dim)
                                            continue;
                                        //找到数集，从其他数格里判断有没有数集里的数字
                                        List<Point> ps = new List<Point>();
                                        List<number> exnml = new List<number>();
                                        foreach (number num in nzl)
                                        {
                                            //因为get_group取得的数格集合不包括数格自己，所以经过交集得出来的nzl不包含矩形数格
                                            //需要检查nl，因为必须也不是形成集合的数格(集合包括expts和nl里记录了位置的数格
                                            if (num.value > 0)
                                                continue;
                                            bool findexpt = true;
                                            foreach (int n in nl)
                                            {
                                                if (num.xy == nzl[n].xy)
                                                    findexpt = false;
                                            }
                                            if (!findexpt) continue;
                                            bool hascand = false;
                                            foreach (int nc in cands)
                                            {
                                                if (num[nc - 1] == pubfun.Flag.normal)
                                                {
                                                    hascand = true;
                                                    break;
                                                }
                                            }
                                            if (hascand)
                                                exnml.Add(num);
                                        }
                                        if (exnml.Count > 0)
                                        {
                                            //找到因为数集而排除的数格，得出结论
                                            List<Point> eps = new List<Point>();
                                            foreach (number num in exnml)
                                                eps.Add(num.xy);
                                            List<Point> nps = new List<Point>();
                                            foreach (int n in nl)
                                                nps.Add(nzl[n].xy);
                                            operation.SolveHelper helper = operation.SolveHelper.UniqueRectangle3;
                                            String str = "唯一矩形" + pubfun.strPoints(pts) + pubfun.strListInt(cis) + "(" + helper.ToString() + ")里，数格" + pubfun.strPoints(expts) + "与" + pubfun.strPoints(nps) + "形成数集" + pubfun.strListInt(cands) + "排除" + pubfun.strPoints(eps) + "里的候选数" + pubfun.strListInt(cands);
                                            Debug.WriteLine(str);
                                            operation op = new operation(helper, operation.opname.set_candidate_none, eps.ToArray(), cands.ToArray(), str);
                                            pts.InsertRange(pts.Count, nps);
                                            op.tip_points = pts;
                                            op.tip_number = cis;
                                            ops.Add(op);
                                            if (isSingleStep) return;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        //按取代旧的XY_Wing解法（Y-Wing与XY-Wing一样）
        void helper_XY_Wing(List<operation> ops)
        {
            if (ops.Count > 0)
                return;
            foreach (number nab in nums)
            {
                List<int> ncab = new List<int>();
                ncab.InsertRange(0, nab.candidates());
                if (ncab.Count != 2)
                    continue;
                List<number> nlab = pz.get_group(nab.xy);
                for (int i = 0; i < nlab.Count - 1; ++i)
                {
                    number nac = nlab[i];
                    List<int> ncac = new List<int>();
                    ncac.InsertRange(0, nac.candidates());
                    if (ncac.Count != 2)
                        continue;
                    List<int> abac = pubfun.intersection_int(ncab, ncac); //ab ,ac的交集
                    if (abac.Count != 1)
                        continue;
                    for (int j = i + 1; j < nlab.Count; ++j)
                    {
                        number nbc = nlab[j];
                        List<int> ncbc = new List<int>();
                        ncbc.InsertRange(0, nbc.candidates());
                        if (ncbc.Count != 2)
                            continue;
                        List<int> abbc = pubfun.intersection_int(ncab, ncbc); //ab，bc的交集
                        if (abbc.Count != 1)
                            continue;
                        List<int> acbc = pubfun.intersection_int(ncac, ncbc);//ac，bc的交集
                        if (acbc.Count != 1 || acbc[0] == abac[0] || acbc[0] == abbc[0]) //ac和bc相同的数字还必须不能与ab与ac或者ab与bc的交集相同
                            continue;
                        //发现Y-Wing，检查是否有可排除的数格
                        List<number> nlac = pz.get_group(nac.xy);
                        List<number> nlbc = pz.get_group(nbc.xy);
                        List<Point> pts = new List<Point>();
                        foreach (number nc in pubfun.numbers_intersection(nlac.ToArray(), nlbc.ToArray()))
                        {
                            if (nc[acbc[0] - 1] == pubfun.Flag.normal)
                            {
                                pts.Add(nc.xy);
                            }
                        }
                        if (pts.Count > 0)
                        {
                            //找到可以排除的数格了
                            operation.SolveHelper helper = operation.SolveHelper.XY_Wing;
                            List<Point> bpts = new List<Point>();
                            bpts.Add(nac.xy);
                            bpts.Add(nab.xy);
                            bpts.Add(nbc.xy);
                            String str = "在" + pubfun.strPoints(bpts) + "发现了" + helper.ToString() +
                                "，在可以被" + pubfun.strPoints(new Point[] { nac.xy, nbc.xy }) + "看到的" + pubfun.strPoints(pts) + "排除" + acbc[0];
                            operation op = new operation(helper, operation.opname.set_candidate_none, pts.ToArray(), acbc.ToArray(), str);
                            op.tip_points = bpts;
                            ops.Add(op);
                            if (isSingleStep) return;
                        }
                    }
                }
            }
        }
    }
}